<template>
  <main>
    <div class="board">
      <div ref="pieces" class="piece-container">
        <div @click="putPiece(index)" :data-index = index @mouseenter="mouseEnter(index)" @mouseleave="mouseLeave(index)" v-for="(item,index) in grids"></div>
      </div>
      <div></div>
    </div>
    <div class="otherPanel">
      <div>
        <div class="opponentInformation">
          <span>你的对手：</span>
          <span>机器人</span>
        </div>
        <div class="firstInformation">
          <span>你是：</span>
          <span>{{firstShow}}</span>
        </div>
        <div class="pieceInformation">
          <span>你使用的：</span>
          <span>{{statusShow}}</span>
        </div>
        <div class="setContainer">
          <el-switch
              v-model="status"
              :disabled="GameData.isGaming"
              size="large"
              inline-prompt
              style="--el-switch-on-color: #303133; --el-switch-off-color: #DCDFE6"
              active-text="黑子"
              inactive-text="白子"
          />
          <el-switch
              v-model="first"
              :disabled="GameData.isGaming"
              size="large"
              inline-prompt
              style="--el-switch-on-color: #f89898; --el-switch-off-color: #79bbff"
              active-text="后手"
              inactive-text="先手"
          />
        </div>
        <div class="start">
          <el-button :disabled="GameData.isGaming" @click="startGaming(true)" round>开始</el-button>
          <el-button :disabled="!GameData.isGaming" @click="toLose" round>认输</el-button>
          <el-button @click="toBack" round>返回</el-button>
        </div>
      </div>
      <div :class="{Show:GameData.gameType===1}">
        <span>在线房间</span>
      </div>
    </div>
  </main>
</template>

<script setup>
import {computed, onBeforeUnmount, onMounted, reactive, ref, watch} from "vue";
import {useGameDataStore} from "@/stores/game.js";
import {ElMessage} from "element-plus";
import {useRouter} from "vue-router";

const GameData = useGameDataStore();
//获取棋盘实例
const pieces = ref();
const status = ref();
const first = ref();
const grids = reactive([]);
const $router = useRouter();

onMounted(()=>{
  initialAll();
})
onBeforeUnmount(()=>{
  status.value = GameData.nowStatus;
  first.value = GameData.firstHand;
  GameData.changeStatus(0);
  GameData.changeIsGaming(false);
  GameData.changeGameType(-1);
  GameData.changeFirst(0);
})
//监听
const statusWatch = watch(status,(n,o)=>{
  n === true?GameData.changeStatus(1):GameData.changeStatus(0);
})
const panelWatch = watch(GameData.panel,(n,o)=>{
  console.log("棋盘已更新",n);
})
const firstWatch = watch(first,(n,o)=>{
  n === true?GameData.changeFirst(1):GameData.changeFirst(0);
})
//计算属性
const statusShow = computed(()=>{
  return GameData.nowStatus === 0?'白子':'黑子';
})
const firstShow = computed(()=>{
  return GameData.firstHand === 0?'先手':'后手';
})

//挂载后的初始化
const initialAll = ()=>{
  //配合v-for 渲染每一个格子
  renderFrid();
  //初始化棋盘二维数组
  GameData.initialPanel();
  //初始化当前页面关联数据
  status.value = GameData.nowStatus;
  first.value = GameData.firstHand;
  //当前为人机对战
  GameData.changeGameType(0);
}
//认输
const toLose = ()=>{
  toWin(GameData.nowStatus,GameData.nowStatus===0?1:0);
}
//渲染棋盘格
const renderFrid = ()=>{
  for(let i = 0;i<225;i++){
    grids.push(i);
  }
}
//落子后的操作
const putPiece = (index)=>{
  if(!GameData.isGaming){
    ElMessage.warning("请先开始游戏");
    return
  }
  if (isExitPiece(parsePosition(index))){
    GameData.changePanel(parsePosition(index),GameData.nowStatus);
    refreshPanelShow()
    if(judgeWinner(GameData.panel,parsePosition(index),GameData.nowStatus)){
      toWin(GameData.nowStatus,GameData.nowStatus);
    }
    console.log('落子坐标',parsePosition(index));
    if(GameData.isGaming){
      AiPutPiece();
    }
  }
  else {
    ElMessage.warning("此处已有棋子！");
  }
}
//ai下棋的操作
const AiPutPiece = () =>{
  let location = computerDown(GameData.panel,GameData.nowStatus,GameData.nowStatus===0?1:0);
  console.log("AI落子",location);
  GameData.changePanel(location,GameData.nowStatus===0?1:0);
  refreshPanelShow()
  if(judgeWinner(GameData.panel,location,GameData.nowStatus===0?1:0)){
    toWin(GameData.nowStatus,GameData.nowStatus===0?1:0);
  }
}
//获胜操作
const toWin = (playerType,realType)=>{
  if(playerType === realType){
    ElMessage.success("恭喜你赢了");
    GameData.changeIsGaming(false);
  }
  else{
    ElMessage.error("你输给Ai了");
    GameData.changeIsGaming(false);
  }
}
//落子后根据棋盘二维数组显示棋子信息
const refreshPanelShow = ()=>{
  for (let i = 0; i < 15; i++) {
    for (let j = 0; j < 15; j++) {
      if(GameData.panel[i][j] === 0){
        pieces.value.children[i*15+j].classList.value = 'white';
      }
      else if(GameData.panel[i][j] === 1){
        pieces.value.children[i*15+j].classList.value = 'black';
      }
      else {
        pieces.value.children[i*15+j].classList.value = '';
      }
    }
  }
}
//根据索引解析出当前坐标 0 0 为起始坐标
const parsePosition = (number)=>{
  let x = number % 15;
  let y = number / 15;
  return [x,Math.floor(y)];
}
//判断能否放棋子
const isExitPiece = (location)=>{
  return GameData.panel[location[1]][location[0]] === -1;
}
//处理方框显示隐藏
const mouseEnter = (index)=>{
  if (isExitPiece(parsePosition(index))){
    pieces.value.children[index].classList.value = 'hover';
  }
}
const mouseLeave = (index)=>{
  if (isExitPiece(parsePosition(index))){
    pieces.value.children[index].classList.value = '';
  }
}
//开始游戏
const startGaming = (data)=>{
  GameData.initialPanel();
  refreshPanelShow();
  GameData.changeIsGaming(data);
  if(GameData.firstHand === 1 && GameData.gameType === 0){
    AiPutPiece();
  }
}
//返回
const toBack = ()=>{
  $router.back()
}
//判断是否胜利
const judgeWinner = (panel,location,type) =>{
  return !!(lineX(panel, location, type) || lineY(panel, location, type) || slash(panel, location, type) || backSlash(panel, location, type));
}
//遍历时判断落点是否在棋盘内
const isInPanel = (x,y) =>{
  return (y < 15 && y >= 0) && (x < 15 && x >= 0);
}
//横轴判断
const lineX = (panel,location,type) =>{
  let num = 1;
  let lockerOne = true;
  let lockerTwo = true;
  for (let i = 1; i < 5; i++) {
    if(isInPanel(location[1],location[0]+i)){
      panel[location[1]][location[0]+i] === -1? lockerOne = false: '';
      if (lockerOne){
        panel[location[1]][location[0]+i] === type? num++ : '';
      }
    }
    if(isInPanel(location[1],location[0]+i)){
      panel[location[1]][location[0]-i] === -1? lockerTwo = false: '';
      if (lockerTwo){
        panel[location[1]][location[0]-i] === type? num++ : '';
      }
    }
  }
  return num > 4;
}
//纵轴判断
const lineY = (panel,location,type) =>{
  let num = 1;
  let lockerOne = true;
  let lockerTwo = true;
  for (let i = 1; i < 5; i++) {
    if(isInPanel(location[1]+i,location[0])){
      panel[location[1]+i][location[0]] === -1? lockerOne = false: '';
      if(lockerOne){
        panel[location[1]+i][location[0]] === type? num++ : '';
      }
    }
    if(isInPanel(location[1]-i,location[0])){
      panel[location[1]-i][location[0]] === -1? lockerTwo = false: '';
      if(lockerTwo){
        panel[location[1]-i][location[0]] === type? num++ : '';
      }
    }
  }
  return num > 4;
}
const slash = (panel, location, type) =>{
  let num = 1;
  let lockerOne = true;
  let lockerTwo = true;
  for (let i = 1; i < 5; i++) {
    if(isInPanel(location[1]+i,location[0]-i)){
      panel[location[1]+i][location[0]-i] === -1? lockerOne = false: '';
      if (lockerOne){
        panel[location[1]+i][location[0]-i] === type? num++ : '';
      }
    }
    if(isInPanel(location[1]-i,location[0]+i)){
      panel[location[1]-i][location[0]+i] === -1? lockerTwo = false: '';
      if (lockerTwo){
        panel[location[1]-i][location[0]+i] === type? num++ : '';
      }
    }
  }
  return num > 4;
}
const backSlash = (panel, location, type)=>{
  let num = 1;
  let lockerOne = true;
  let lockerTwo = true;
  for (let i = 1; i < 5; i++) {
    if(isInPanel(location[1]-i,location[0]-i)){
      panel[location[1]-i][location[0]-i] === -1? lockerOne = false: '';
      if (lockerOne){
        panel[location[1]-i][location[0]-i] === type? num++ : '';
      }
    }
    if(isInPanel(location[1]+i,location[0]+i)){
      panel[location[1]+i][location[0]+i] === -1? lockerTwo = false: '';
      if (lockerTwo){
        panel[location[1]+i][location[0]+i] === type? num++ : '';
      }
    }
  }
  return num > 4;
}
const chessScore = (playerNum, computerNum)=> {
  // 机器进攻

  // 1.既有人类落子，又有机器落子，判分为0
  if (playerNum > 0 && computerNum > 0) {
    return 0;
  }
  // 2.全部为空没有棋子，判分为7(14)
  if (playerNum === 0 && computerNum === 0) {
    return 14;
  }
  // 3.机器落一子，判分为35(70)
  if (computerNum === 1) {
    return 70;
  }
  // 4.机器落两子，判分为800(1600)
  if (computerNum === 2) {
    return 1600;
  }
  // 5.机器落三子，判分为15000(30000)
  if (computerNum === 3) {
    return 30000;
  }
  // 6.机器落四子，判分为800000(1600000)
  if (computerNum === 4) {
    return 1600000;
  }
  // 机器防守

  // 7.玩家落一子，判分为15(30)
  if (playerNum === 1) {
    return 30;
  }
  // 8.玩家落两子，判分为400(800)
  if (playerNum === 2) {
    return 800;
  }
  // 9.玩家落三子，判分为1800(3600)
  if (playerNum === 3) {
    return 3600;
  }
  // 10.玩家落四子，判分为100000(200000)
  if (playerNum === 4) {
    return 200000;
  }
  return -1; //如果是其他情况，则出现错误，不会执行该段代码
}
const computerDown = (panel,playerType,aiType) => {
  // 初始化score评分组
  let chessWidth = 15;
  let score = new Array(chessWidth);
  for (let i = 0; i < 15; i++) {
    score[i] = new Array(chessWidth).fill(0);
  }
  let playerNum = 0; // 五元组中玩家（黑棋）数量
  let computerNum = 0; // 五元组中电脑（白棋）数量
  let tempScore = 0; // 五元组临时得分
  let maxScore = -1; // 最大得分
  let goalX = -1, goalY = -1; // 最佳位置

  // 横向寻找
  for (let i = 0; i < chessWidth; i++) {
    for (let j = 0; j < chessWidth - 4; j++) {
      for (let k = j; k < j + 5; k++) {
        // 如果是玩家落子
        if (panel[k][i] === playerType) {
          playerNum++;
        } else if (panel[k][i] === aiType) { //如果是电脑落子
          computerNum++;
        }
      }
      // 将每一个五元组中的黑棋和白棋个数传入评分表中
      tempScore = chessScore(playerNum, computerNum);
      // 为该五元组的每个位置添加分数
      for (let k = j; k < j + 5; k++) {
        score[k][i] += tempScore;
      }
      // 清空五元组中棋子数量和五元组临时得分
      playerNum = 0;
      computerNum = 0;
      tempScore = 0;
    }
  }

  // 纵向寻找
  for (let i = 0; i < chessWidth; i++) {
    for (let j = 0; j < chessWidth - 4; j++) {
      for (let k = j; k < j + 5; k++) {
        if (panel[i][k] === playerType) {
          playerNum++;
        } else if (panel[i][k] === aiType) {
          computerNum++;
        }
      }
      tempScore = chessScore(playerNum, computerNum);
      for (let k = j; k < j + 5; k++) {
        score[i][k] += tempScore;
      }
      playerNum = 0;
      computerNum = 0;
      tempScore = 0;
    }
  }
  // 反斜线寻找
  // 反斜线上侧部分
  for (let i = chessWidth - 1; i >= 4; i--) {
    for (let k = i, j = 0; j < chessWidth && k >= 0; j++, k--) {
      let m = k; //x 14 13
      let n = j; //y 0  1
      for (; m > k - 5 && m >= 0 && n < chessWidth; m--, n++) {
        if (panel[m][n] === playerType) {
          playerNum++;
        } else if (panel[m][n] === aiType) {
          computerNum++;
        }
      }
      // 注意在斜向判断时，可能出现构不成五元组（靠近棋盘的四个顶角）的情况，所以要忽略这种情况
      if (m === k - 5) {
        tempScore = chessScore(playerNum, computerNum);
        for (m = k, n = j; m > k - 5 && m >= 0 && n < chessWidth; m--, n++) {
          score[m][n] += tempScore;
        }
      }
      playerNum = 0;
      computerNum = 0;
      tempScore = 0;
    }
  }
  // 反斜线下侧部分
  for (let i = 1; i < 15; i++) {
    for (let k = i, j = chessWidth - 1; j >= 0 && k < 15; j--, k++) {
      let m = k; //y 1
      let n = j; //x 14
      for (; m < k + 5 && m < chessWidth && n >= 0; m++, n--) {
        if (panel[n][m] === playerType) {
          playerNum++;
        } else if (panel[n][m] === aiType) {
          computerNum++;
        }
      }
      // 注意在斜向判断时，可能出现构不成五元组（靠近棋盘的四个顶角）的情况，所以要忽略这种情况
      if (m === k + 5) {
        tempScore = chessScore(playerNum, computerNum);
        for (m = k, n = j; m < k + 5 && m < chessWidth && n >= 0; m++, n--) {
          score[n][m] += tempScore;
        }
      }
      playerNum = 0;
      computerNum = 0;
      tempScore = 0;
    }
  }

  // 正斜线寻找
  // 正斜线上侧部分
  for (let i = 0; i < chessWidth - 1; i++) {
    for (let k = i, j = 0; j < chessWidth && k < chessWidth; j++, k++) {
      let m = k;
      let n = j;
      for (; m < k + 5 && m < chessWidth && n < chessWidth; m++, n++) {
        if (panel[m][n] === playerType) {
          playerNum++;
        } else if (panel[m][n] === aiType) {
          computerNum++;
        }
      }
      // 注意在斜向判断时，可能出现构不成五元组（靠近棋盘的四个顶角）的情况，所以要忽略这种情况
      if (m === k + 5) {
        tempScore = chessScore(playerNum, computerNum);
        for (m = k, n = j; m < k + 5 && m < chessWidth && n < chessWidth; m++, n++) {
          score[m][n] += tempScore;
        }
      }
      playerNum = 0;
      computerNum = 0;
      tempScore = 0;
    }
  }

  // 正斜线下侧部分
  for (let i = 1; i < chessWidth - 4; i++) {
    for (let k = i, j = 0; j < chessWidth && k < chessWidth; j++, k++) {
      let m = k;
      let n = j;
      for (; m < k + 5 && m < chessWidth && n < chessWidth; m++, n++) {
        if (panel[n][m] === playerType) {
          playerNum++;
        } else if (panel[n][m] === aiType) {
          computerNum++;
        }
      }
      // 注意在斜向判断时，可能出现构不成五元组（靠近棋盘的四个顶角）的情况，所以要忽略这种情况
      if (m === k + 5) {
        tempScore = chessScore(playerNum, computerNum);
        for (m = k, n = j; m < k + 5 && m < chessWidth && n < chessWidth; m++, n++) {
          score[n][m] += tempScore;
        }
      }
      playerNum = 0;
      computerNum = 0;
      tempScore = 0;
    }
  }

  // 从空位置中找到得分最大的位置
  for (let i = 0; i < chessWidth; i++) {
    for (let j = 0; j < chessWidth; j++) {
      if (panel[i][j] === -1 && score[i][j] > maxScore) {
        goalX = i;
        goalY = j;
        maxScore = score[i][j];
      }
    }
  }
  if (goalX !== -1 && goalY !== -1 && panel[goalX][goalY] === -1) {
    return [goalY,goalX];
  }
}


</script>

<style lang="less" scoped>
@shadow-color: #f3d19e;
@info-active: #79bbff;
@info-weight-active: 600;
@info-weight-family: 微软雅黑;

.board{
  height: 600px;
  width: 600px;
  position: relative;
  background-color: white;
  display: flex;
  flex-direction:column;
  justify-content:center;
  align-items:center;

  >div:last-child{
    margin: 30px 30px;
    height: 540px;
    width: 540px;
    border-radius: 20px;
    box-shadow: 0px 0px 5px @shadow-color;
    background: url("@/assets/img/wuziqi.png") no-repeat center center;
  }
  .piece-container{
    position: absolute;
    margin: 30px 30px;
    height: 540px;
    width: 540px;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    flex-wrap: wrap;

    div{
      margin: 0;
      height: 36px;
      width: 36px;

    }
    div.black{
      background: url("@/assets/img/black.png") no-repeat center center;
    }
    div.white{
      background: url("@/assets/img/white.png") no-repeat center center;
    }
    div.hover{
      background: url("@/assets/img/hoverUp.png") no-repeat center center;
    }
  }
}
.otherPanel{
  width: fit-content;
  height: 500px;

  >div:nth-child(1){
    margin: 0 auto;
    width: 30%;
    min-width: 250px;
    max-width: 350px;
    box-shadow: 0px 0px 5px @shadow-color;
    border-radius: 10px;
    padding-top: 5px;
    height: 200px;
    .el-switch{
      width: 80px;
      height: 30px;
    }
    .univInfo(){
      font-size: 18px;
      font-weight: 500;
      font-family:仿宋;
      margin: 10px 10px;
    }
    .opponentInformation{
      .univInfo();

      :last-child{
        color: @info-active;
        font-weight: @info-weight-active;
        font-family: @info-weight-family;
      }
    }
    .firstInformation{
      .univInfo();

      :last-child{
        color: @info-active;
        font-weight: @info-weight-active;
        font-family: @info-weight-family;
      }
    }
    .pieceInformation{
      .univInfo();
      :last-child{
        color: @info-active;
        font-weight: @info-weight-active;
        font-family: @info-weight-family;
      }
    }
    .setContainer{
      margin: 10px 10px;
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
    }
    .start{
      height: 30px;
      text-align: center;
      display: flex;
      flex-direction: row;
      justify-content: space-evenly;
      align-items: center;
    }
  }
  >div:nth-child(2){
    margin: 20px 10px;
    width: 500px;
    height: 300px;
    border-radius: 10px;
    opacity: 0;
    box-shadow: 0px 0px 5px @shadow-color;
    transition: 0.5s all ease-in-out;
  }
  >div:nth-child(2).Show{
    opacity: 1;
    transform: translateY(10px);
  }
}
main{
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  min-width: 1000px;
  max-width: 1500px;
  margin: 0 auto;
}
</style>